(function(jQuery) {
	jQuery.fn.checkboxTree = function(settings) {

		settings = jQuery.extend({
			collapsedarrow: "img-arrow-collapsed.gif",
			expandedarrow: "img-arrow-expanded.gif",
			blankarrow: "img-arrow-blank.gif",
			activeClass: "checkboxtreeactive",
			hoverClass: "over",
			checkchildren: false,
			checkparents: true,
			collapsed: true,
			hidecbwithjs:false,
			smartclick:true,
			checkedClass: "checked",
			multiclick:true
		}, settings);

		var $group = this;
		var $labels = jQuery(":checkbox + label",$group)
		var $checkboxes = jQuery(":checkbox",$group)

		//set up the tree
		jQuery("li",$group).each(function(){

			var $this = jQuery(this)
			var $collapseImage;

			if(settings.checkparents){
				var checkedchildren = jQuery("ul li input:checked",$this).length
				var $firstcheckbox = $this.children("input:checkbox:first")
				
        		var my_numofchildren = jQuery("ul li input",$this).length;
        		var my_checkedchildren = jQuery("ul li input:checked",$this).length;
        		
				if((!$this.children("input:checkbox:first").is(":checked")) && (checkedchildren>0) && (checkedchildren==my_numofchildren)){
					$firstcheckbox.attr("checked","checked")
				}        		
			}

			if($this.is(":has(ul)")){
				if(($this.attr('id')=='tree_root')){
				    var tmp_class = " tree_root";
				}else{
				    var tmp_class = '';
				}

				if(settings.collapsed){
					$this.find("ul").hide();
					$collapseImage = jQuery('<img class="checkboxtreeimage'+tmp_class+'" src="' + settings.collapsedarrow + '" / >')
					$collapseImage.data("collapsedstate",0)
				}else{
					$collapseImage = jQuery('<img class="checkboxtreeimage'+tmp_class+'" src="' + settings.expandedarrow + '" / >')
					$collapseImage.data("collapsedstate",1)
				}
			}else{
				$collapseImage = jQuery('<img src="' + settings.blankarrow + '" / >')
			}
			$this.prepend($collapseImage);
			
		})

		//add class signifying the tree has been setup
		$group.addClass(settings.activeClass);

		$group.bind("click.checkboxtree",function(e,a){
			var $clicked = jQuery(e.target)
			var $clickedcheck = $clicked.prev()
			var $currrow = $clicked.parents("li:first")
			var $clickedparent = $currrow.parents("li:first").find(":checkbox:first");
			var $clickedparentlabel = $clickedparent.next("label");
			var clickedlabel = false;
			var clickedimage = false;
			if($clicked.is(":checkbox + label")){
				clickedlabel=true;
			}
			if($clicked.is("img.checkboxtreeimage")){
				clickedimage=true;
			}
			//when the label is clicked, set the checkbox to the opposite clicked state, and toggle the checked class
			if(clickedlabel){
				$clicked.prev().attr({checked: !$clickedcheck.attr("checked")}).end().toggleClass(settings.checkedClass);

				//check child checkboxes if settings say so
				if(settings.checkchildren&&a!=="checkparents"){
					$currrow.find(":checkbox + label").prev().attr({checked: $clickedcheck.attr("checked")?"checked":""})
					.next()
					.addClass($clicked.hasClass(settings.checkedClass)?settings.checkedClass:"")
					.removeClass($clicked.hasClass(settings.checkedClass)?"":settings.checkedClass)
				}
				
				//check parents if that option is set
//				if(settings.checkparents){
//					var checkedchildren = jQuery("input:checked",$currrow).length;
//					
//					if((!$clickedparent.is(":checked")) && (checkedchildren>0) ){
//						$clickedparentlabel.trigger("click.checkboxtree",["checkparents"]);
//					}
//					
//				}			

			}
			
	
    		if(settings.smartclick){			
                checkboxtreeparentrunner($clicked);
		    }
		    
		    if(!settings.multiclick)
		    {
		        if($clicked.attr('tagName') == 'LABEL')
		        {
		           checkboxtreeonlyonechecked($clicked);
		        }
		    }
		    
			//handle expanding of levels
			if(clickedimage){
				var clickstate=$clicked.data("collapsedstate")
				if(clickstate===0){
					$currrow.children("ul").show();
					$currrow.children("img").attr("src",settings.expandedarrow);
					$clicked.data("collapsedstate",1)
				}else if(clickstate===1){
					$currrow.children("ul").hide();
					$currrow.children("img").attr("src",settings.collapsedarrow);
					$clicked.data("collapsedstate",0)
				}
			}

		})
		
		//set the class correctly for the labels that contain checked checkboxes
		jQuery("input:checked + label",$group).addClass(settings.checkedClass);
		

		//add hover class for labels if is ie 6
		if(jQuery.browser.msie&&jQuery.browser.version<7){
			$labels.hover( 
				function(){jQuery(this).addClass(settings.hoverClass)},
				function(){jQuery(this).removeClass(settings.hoverClass); }
			)
		}		

		//hide the checkboxes with js if set option set to true
		if(settings.hidecbwithjs){
			$checkboxes.hide();
		}

		return $group;
	};
	
	var checkboxtreeparentsetter = function($clicked){
	    $clickedparentlabel = $clicked.parents("li:first").parents("li:first").find(":checkbox:first").next("label");
		var my_numofchildren = $clickedparentlabel.next().children().children("input").length;
        var my_checkedchildren = $clickedparentlabel.next().children().children("input:checked").length;
		
		if(my_numofchildren > 0 && (my_checkedchildren ==0 || my_checkedchildren >0) ){		
    		if(my_checkedchildren > 0 && my_checkedchildren<my_numofchildren){
    		    // set all parent as half completed
    			 $clickedparentlabel.removeClass("checked");
    			 $clickedparentlabel.prev().attr('checked',false);
    		}else if(my_checkedchildren > 0 && my_checkedchildren==my_numofchildren){
    		    // set all parent as completed
    			 $clickedparentlabel.addClass("checked");
    			 $clickedparentlabel.prev().attr('checked','checked');
    		}else if(my_checkedchildren==0){
    		    // set all parent as unchecked
    			 $clickedparentlabel.removeClass("checked");
    		}
		}
		
	}
	
	var checkboxtreeparentrunner = function($clicked){
	    var $parent = $clicked.parents("li:first").parents("li:first").find(":checkbox:first").next("label");
	    var $parent_input = $clicked.parents("li:first").parents("li:first").find(":checkbox:first");
	    if($parent.html()){
	        checkboxtreeparentsetter($clicked);
	        checkboxtreeparentrunner($parent_input);
	    }
	}
	
	var checkboxtreeonlyonechecked = function($clicked){
	    var $parent = $clicked.closest('.checkboxtreeactive');
	    $parent.find('input[type=checkbox]:checked').not($clicked.prev()).each(function(){
	        $(this).removeAttr('checked');
	        $(this).next().removeClass('checked');
	    });
	}

})(jQuery);

